package com.db.williamchart.view;

import com.db.williamchart.*;
import com.db.williamchart.animation.ChartAnimation;
import com.db.williamchart.animation.DefaultAnimation;
import com.db.williamchart.data.*;
import com.db.williamchart.data.configuration.ChartConfiguration;
import com.db.williamchart.extensions.AttrUtils;
import com.db.williamchart.extensions.ListEx;
import com.db.williamchart.plugin.AxisGrid;
import com.db.williamchart.plugin.AxisLabels;
import com.db.williamchart.renderer.RendererConstants;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.StackLayout;
import ohos.agp.render.Canvas;
import ohos.agp.text.Font;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;
import ohos.utils.Pair;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

public abstract class AxisChartView extends ComponentContainer {

    private static final int defaultFrameWidth = 200;
    private static final int defaultFrameHeight = 100;
    private static final int defaultLabelsSize = 60;
    private final List<Pair<String,Float>> editModeSampleData = new ArrayList<>();

    public int labelsSize = defaultLabelsSize;
    public int labelsColor = -0x1000000;

    public Font labelsFont = null;

    public AxisType axis = AxisType.XY;

    public Scale scale = new Scale(RendererConstants.NOT_INITIALIZED, RendererConstants.NOT_INITIALIZED);

    public String labelsFormatter;

    protected ChartAnimation<DataPoint> animation = new DefaultAnimation();

    public Labels labels = new AxisLabels();

    public Tooltip tooltip = new Tooltip() {
        @Override
        public void onCreateTooltip(ComponentContainer parent) {

        }

        @Override
        public void onDataPointTouch(Float x, Float y) {

        }

        @Override
        public void onDataPointClick(Float x, Float y) {

        }
    };

    public Grid grid = new Grid() {
        @Override
        public void draw(Canvas canvas, Frame innerFrame, List<Float> xLabelsPositions, List<Float> yLabelsPositions) {

        }
    };

    private OnDataPointTouchListener onDataPointTouchListener;

    protected Canvas canvas;

    protected Painter painter = new Painter();

    protected ChartContract.Renderer renderer;

    abstract ChartConfiguration getChartConfiguration();

    public AxisChartView(Context context) {
        super(context);
        init(null);
    }

    public AxisChartView(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init(attrSet);
    }

    public AxisChartView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init(attrSet);
    }

    private boolean isPreDraw = false;
    private void init(AttrSet attrSet){
        editModeSampleData.add(new Pair<>("Label1",1f));
        editModeSampleData.add(new Pair<>("Label2",7.5f));
        editModeSampleData.add(new Pair<>("Label3",4.7f));
        editModeSampleData.add(new Pair<>("Label4",3.5f));

        handleAttrSet(attrSet);
        addDrawTask(new DrawTask() {
            @Override
            public void onDraw(Component component, Canvas canvas) {
                tooltip.onCreateTooltip(AxisChartView.this);

            }
        },DrawTask.BETWEEN_BACKGROUND_AND_CONTENT);
        addDrawTask(new DrawTask() {
            @Override
            public void onDraw(Component component, Canvas canvas) {
                if (AxisChartView.this.canvas == null){
                    AxisChartView.this.canvas = canvas;
                }

                if (renderer != null){
                    if (!isPreDraw){
                        isPreDraw = renderer.preDraw(getChartConfiguration());
                    }
                    renderer.draw();
                }
            }
        });
        setTouchEventListener(new TouchEventListener() {
            @Override
            public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
                Triple<Integer, Float, Float> integerFloatFloatTriple = renderer.processTouch(getTouchX(touchEvent, 0), getTouchY(touchEvent, 0));
                if (integerFloatFloatTriple.getFirst() != -1){
                    if (onDataPointTouchListener != null){
                        onDataPointTouchListener.onDataPointTouch(integerFloatFloatTriple.getFirst(),integerFloatFloatTriple.getSecond(),integerFloatFloatTriple.getThird());
                    }
                    tooltip.onDataPointTouch(integerFloatFloatTriple.getSecond(),integerFloatFloatTriple.getThird());
                }
                return true;
            }
        });
    }
    private float getTouchX(TouchEvent touchEvent, int index) {
        float x = 0;
        if (touchEvent.getPointerCount() > index) {
            int[] xy = getLocationOnScreen();
            if (xy != null && xy.length == 2) {
                x = touchEvent.getPointerScreenPosition(index).getX() - xy[0];
            } else {
                x = touchEvent.getPointerPosition(index).getX();
            }
        }
        return x;
    }

    private float getTouchY(TouchEvent touchEvent, int index) {
        float y = 0;
        if (touchEvent.getPointerCount() > index) {
            int[] xy = getLocationOnScreen();
            if (xy != null && xy.length == 2) {
                y = touchEvent.getPointerScreenPosition(index).getY() - xy[1];
            } else {
                y = touchEvent.getPointerPosition(index).getY();
            }
        }
        return y;
    }

    public void setOnDataPointTouchListener(OnDataPointTouchListener onDataPointTouchListener) {
        this.onDataPointTouchListener = onDataPointTouchListener;
    }

    public void show(LinkedHashMap<String,Float> entries){
//        addDrawTask(new DrawTask() {
//            @Override
//            public void onDraw(Component component, Canvas canvas) {
//                renderer.preDraw(getChartConfiguration());
//
//            }
//        },DrawTask.BETWEEN_BACKGROUND_AND_CONTENT);
        renderer.render(ListEx.toList(entries));
    }
    public void animate(LinkedHashMap<String,Float> entries){
//        addDrawTask(new DrawTask() {
//            @Override
//            public void onDraw(Component component, Canvas canvas) {
//                renderer.preDraw(getChartConfiguration());
//
//            }
//        },DrawTask.BETWEEN_BACKGROUND_AND_CONTENT);
        renderer.anim(ListEx.toList(entries),animation);
    }
    public void show(List<Pair<String,Float>> entries){
//        addDrawTask(new DrawTask() {
//            @Override
//            public void onDraw(Component component, Canvas canvas) {
//                renderer.preDraw(getChartConfiguration());
//
//            }
//        },DrawTask.BETWEEN_BACKGROUND_AND_CONTENT);
        renderer.render(entries);
    }
    public void animate(List<Pair<String,Float>> entries){
//        addDrawTask(new DrawTask() {
//            @Override
//            public void onDraw(Component component, Canvas canvas) {
//                renderer.preDraw(getChartConfiguration());
//
//            }
//        },DrawTask.BETWEEN_BACKGROUND_AND_CONTENT);
        renderer.anim(entries,animation);
    }
    private void handleAttrSet(AttrSet attrSet){
        switch (AttrUtils.getStringFromAttr(attrSet,"chart_axis","none")){
            case "x":
                axis = AxisType.X;
                break;
            case "y":
                axis = AxisType.Y;
                break;
            case "xy":
                axis = AxisType.XY;
                break;
            default:
                axis = AxisType.NONE;
                break;
        }

        labelsSize = AttrUtils.getDimensionFromAttr(attrSet,"chart_labelsSize",defaultLabelsSize);

        labelsColor = AttrUtils.getColorFromAttr(attrSet,"chart_labelsColor",labelsColor);
        String font = AttrUtils.getStringFromAttr(attrSet,"chart_labelsFont","");

        if (font != null){
            if (!font.isEmpty()){
                File file = AttrUtils.resPathToFile(getContext(),font);
                Font.Builder builder = new Font.Builder(file);
                labelsFont = builder.build();
                painter.setLabelFont(labelsFont);
            }
        }
        String g = AttrUtils.getStringFromAttr(attrSet,"chart_grid","");
        if (!g.isEmpty()){
            grid = new AxisGrid();
            switch (g){
                case "vertical":
                    ((AxisGrid)grid).setGridType(AxisGrid.GridType.VERTICAL);
                    break;
                case "horizontal":
                    ((AxisGrid)grid).setGridType(AxisGrid.GridType.HORIZONTAL);
                    break;
                default:
                    ((AxisGrid)grid).setGridType(AxisGrid.GridType.FULL);
                    break;
            }

            ((AxisGrid)grid).setColor(AttrUtils.getColorFromAttr(attrSet,"chart_gridColor",labelsColor));
            ((AxisGrid)grid).setStrokeWidth(AttrUtils.getFloatFromAttr(attrSet,"chart_gridStrokeWidth",((AxisGrid) grid).getStrokeWidth()));
            String gridEffect = AttrUtils.getStringFromAttr(attrSet,"chart_gridEffect","");
            switch (gridEffect){
                case "dashed":
                    ((AxisGrid)grid).setGridEffect(AxisGrid.GridEffect.DASHED);
                    break;
                case "dotted":
                    ((AxisGrid)grid).setGridEffect(AxisGrid.GridEffect.DOTTED);
                    break;
                default:
                    ((AxisGrid)grid).setGridEffect(AxisGrid.GridEffect.SOLID);
                    break;
            }
        }

    }

    public ChartAnimation<DataPoint> getAnimation() {
        return animation;
    }

    public void setAnimationDuration(long duration){
        if (animation != null){
            animation.setDuration(duration);
        }
    }

    public void setAnimation(ChartAnimation<DataPoint> animation) {
        this.animation = animation;
    }

    protected void handleEditMode(){

    }

    public interface OnDataPointTouchListener{
        void onDataPointTouch(int index,Float x,Float y);
    }
}
